package gfs;

import java.util.*;

/**
 * This class allows you to make a coordinate with the specified x and y integer
 * values and have a method for making <code>ArrayList</code> of coordinates for
 * a graph.
 * 
 * @author Mark Vimonte
 * @author Joel Jauregui
 * @version 1.8 2008/7/7
 */

public class Coordinate extends Object
    {
    
    /** The maximum x value */
    public static final int MAX_X = 300;

    /** The maximum y value */
    public static final int MAX_Y = 300;

    /** The minimum x value */
    public static final int MIN_X = -300;

    /** The minimum y value */
    public static final int MIN_Y = -300;

    /** The default radius for a circle */
    public static final int DEFAULT_RADIUS = 30;

    /** The default number of sides */
    public static final int DEFAULT_NUMSIDE = 10;

    /** The maximum pen width */
    public static final int MAX_PEN_WIDTH = 3;

    /** The minimum pen width */
    public static final int MIN_PEN_WIDTH = 1;

    private int x;
    private int y;
    private int row;
    private int col;
        
	/**
	 * Constructs an Coordinate object with specified x and y positions
	 * 
	 * @param xC the x coordinate of the <code>Coordinate</code> object 
	 * @param yC the y coordinate of the <code>Coordinate</code> object 
	 * @exception throws <code>IllegalArgumentException</code> if the coordinates
	 * are outside of thw viewable window.
	 */
    public Coordinate(int xC, int yC) 
    	{
    	super();
    	if(xC > MAX_X)
			throw new IllegalArgumentException("Illegal X Coordinate: " 
			+ "Out of Display");
		if(xC < MIN_X)
			throw new IllegalArgumentException("Illegal X Coordinate: " 
			+ "Out of Display");
		if(yC > MAX_Y)
			throw new IllegalArgumentException("Illegal Y Coordinate: " 
			+ "Out of Display");
		if(yC < MIN_Y)
			throw new IllegalArgumentException("Illegal Y Coordinate: " 
			+ "Out of Display");        
    	x = xC;
    	y = yC;
        row = 9 - (y + 270)/60;
        col = (x + 270)/60;
    	}
    
    public Coordinate(Integer row, Integer col)
        {
        super();
        if(row < 0)
            throw new IllegalArgumentException("Row cannot be less than 0");
        if(col < 0)
            throw new IllegalArgumentException("Column cannot be less than 0");
        if(row >= 10)
            throw new IllegalArgumentException("Row cannot be greater than 9");
        if(col >= 10)
            throw new IllegalArgumentException("Column cannot be greater than 9");
        this.row = row.intValue();
        this.col = col.intValue();
        x = 60 * col - 270;
        y = 60 * (9 - row) - 270;
        }
    
    public Coordinate(Coordinate coor)
        {
        this(coor.getX(), coor.getY());
        }
    
        /**
         * Input the min and max X and Y values for the graph you are making 
         * coordinates for then input how many boxes you want on the sides
 	 * it will then return to you an array of coordinates that have a center 
         * in each of the squares. 
         * 
         * @param xMin
         *      The minimum x value of the graph you are making coordinates for
         * @param xMax
         *      The maximum x value of the graph you are making coordinates for
         * @param yMin
         *      The minimum y value of the graph you are making coordinates for
         * @param yMax
         *      The maximum y value of the graph you are making coordinates for
         * @param numberPerSide
         *      The number of coordinates you want per side
         * @return
         *      The <code>ArrayList</code> of coordinates made to the specified
         * xMin, xMax, yMin, yMax, and numberPerSide values
         */
    public static ArrayList<Coordinate> getArrayList(int xMin, int xMax,
     int yMin, int yMax, int numberPerSide)
     	{
     	int xSpan = Math.abs(xMin) + Math.abs(xMax);
     	int ySpan = Math.abs(yMax) + Math.abs(yMin);
     	if(xMin == xMax || yMin == yMax)
			throw new IllegalArgumentException("Illegal X or Values: " +
            		"Equal min and max values");
		if(xSpan < numberPerSide || ySpan < numberPerSide)
			throw new IllegalArgumentException("Illegal Number of Sides: " +
            		"Cannot have a box with an X or Y less than 1");                        
     	ArrayList<Coordinate> zz = new ArrayList<Coordinate>(numberPerSide*numberPerSide);
     	int xAmountPerSq = xSpan/numberPerSide;
     	int yAmountPerSq = ySpan/numberPerSide;
     	int xIncrement = xAmountPerSq;
     	int yIncrement = yAmountPerSq;
     	for (int i = 0, xStart = xMin + xIncrement/2, yStart = 
                yMax - yIncrement/2; i < numberPerSide * numberPerSide; i++)
     		{
     		zz.add(new Coordinate(xStart,yStart));
     		if ((i + 1) % numberPerSide == 0)
				{
				yStart -= yIncrement;
				xStart = xMin + xIncrement/2;
				}
			else
				xStart += xIncrement;
		}
     	return zz;
     	}
    
    /**
     * Gets a <code>Coordinate</code> From the Hash Number
     * 
     * @param hash 
     *      hash number
     * @deprecated This thing is shit like O(n^4) shit...yeah....
     * @return 
     *      <code>Coordinate</code> from the hash code
     */ 
    public static Coordinate getCoordinateFromHashNumber(int hash)
        {
        for (Coordinate cd : getArrayList(MIN_X, MAX_X, MIN_Y, MAX_Y, 
                DEFAULT_NUMSIDE))
            if (hash == cd.hashCode())
                return cd;
        return null;
        }
    
    /**
     * Gets a <code>Coordinate</code> from the hash number
     * 
     * @param hash
     *      The hash number
     * @return
     *      The <code>Coordinate</code> with designated hash number
     */
    public static Coordinate getCoorFromHash(int hash)
        {
        if(hash < 10)
            return new Coordinate(new Integer(0), new Integer(hash));
        else
            {
            int c = hash % 10, r = hash / 10;
            Integer col = new Integer(c), row = new Integer(r);
            return new Coordinate(row, col);
            }
        }
    
    /**
     * Accessor function that returns x coordinate
     * @return X
     */
    public int getX()
    	{
    	return x;
    	}
    
    /**
     * Accessor function that returns y coordinate
     */
    public int getY()
    	{
    	return y;
    	}
        
    /**
     * Returns the row of this <code>Coordinate</code>
     * 
     * @deprecated This method is replaced by row which returns the field row 
     * instead of calculating it
     * @return The row
     * @see gfs.Coordinate#row()
     */    
    @Deprecated
    public int getRow()
        {        
        return 9 - (getY() + 270)/60;
        }
        
    /**
     * Returns the column of this <code>Coordinate</code>
     * 
     * @deprecated This method is replaced by col() which returns the field col 
     * instead of calculating it
     * @return The column
     * @see gfs.Coordinate#col() 
     */
    @Deprecated
    public int getCol()
        {        
        return (getX() + 270)/60;
        }
    
    /**
     * Returns the row of this coordinate 
     * 
     * @return
     *      The row of the coordinate
     */
    public int row()
        {
        return row;
        }
    
    /**
     * Returns the column of this coordinate
     * 
     * @return
     *      The column of the coordinate
     */
    public int col()
        {
        return col;
        }
    
    /**
     * Returns a <code>Coordinate</code> mirrored across the x and y axis
     * 
     * @return The mirrored <code>Coordinate</code>
     */   
    public Coordinate getMirroredCoordinate()
        {
        return new Coordinate(getX() * -1, getY() * -1);
        }
   
    @Override
    public boolean equals(Object obj) {
        if (obj == null)            
            return false;            
        if (getClass() != obj.getClass())           
            return false;            
        Coordinate other = (Coordinate) obj;
        if (this.x != other.getX())
            return false;
        if (this.y != other.getY())
            return false;
        return true;
        }

    @Override
    public int hashCode() 
        {
        return row() * 10 + col();
        }

    @Override
    public String toString()
    	{
    	return "My X coordinate is " + x + " and my Y coordinate is " + y + "."
                + "\n Row:" + row() + " Col:" + col();
    	}
    }